/*
 * GoogleLogic.java
 */

package pl.edu.pw.mini.gui;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import pl.edu.pw.mini.DirtyLogHelper;
import pl.edu.pw.mini.adapter.GoogleAdapter;
import pl.edu.pw.mini.adapter.OpenOfficeAdapter;
import pl.edu.pw.mini.adapter.documents.Document;
import pl.edu.pw.mini.adapter.documents.GoogleDocument;
import pl.edu.pw.mini.adapter.documents.OpenOfficeTextDocument;
import pl.edu.pw.mini.adapter.documents.OpenOfficeWorkbook;
import pl.edu.pw.mini.exceptions.ConnectionException;
import pl.edu.pw.mini.exceptions.InternalException;
import pl.edu.pw.mini.exceptions.OpenOfficeException;
import pl.edu.pw.mini.state.StateManager;
import pl.edu.pw.mini.adapter.OpenOfficeAdapter.ExportType;
/**
 *
 * @author cdendek
 */
public class GoogleInterfaceLogic implements IInterfaceLogic{
    
    private static GoogleInterfaceLogic gLogic=new GoogleInterfaceLogic();
    
    /** Creates a new instance of GoogleLogic */
    private GoogleInterfaceLogic() {
    }
    
    public static GoogleInterfaceLogic getInstance(){
        return gLogic;
    }
    
    static abstract class ExceptionalRunner implements Runnable{
        private Object returnValue;
        private Throwable topThrowable;
        
        public abstract Object runInternal() throws Throwable;
        public void run(){
            try{
                returnValue=runInternal();
            } catch(Throwable t){
                topThrowable=t;
            }
        }
        
        public Throwable getTopThrowable(){
            return topThrowable;
        }
        public Object getReturnValue(){
            return returnValue;
        }
    }
    public static void upload(String title) throws OpenOfficeException, InternalException, ConnectionException{
        upload(null,title);
    }
    public static void uploadTextDocument(String title,OpenOfficeTextDocument doc) throws OpenOfficeException, InternalException, ConnectionException{
       final File tmpFile= OpenOfficeAdapter.saveDocumentInTempFile(doc,ExportType.DOC);
       if (title==null || "".equals(title)){
            title=doc.getTitle();
        }
        final String documentTitle=title;
                ExceptionalRunner excRun=new ExceptionalRunner(){
            public Object runInternal() throws OpenOfficeException, InternalException, ConnectionException {
                GoogleAdapter.getAdapter().uploadFile(StateManager.getGoogle(),tmpFile,documentTitle);
                return null;
            }
            
        };
        try{
            executeExceptionalRunner(excRun);
        } catch(Exception ex){
            Throwable t=ex.getCause();
            if (t instanceof OpenOfficeException){
                throw (OpenOfficeException)t;
            }
            if (t instanceof InternalException){
                throw (InternalException)t;
            }
            if (t instanceof ConnectionException){
                throw (ConnectionException)t;
            }
            DirtyLogHelper.append(ex);
            DirtyLogHelper.append(t);
            throw new InternalException(t);
        }
        tmpFile.delete();
    }
    public static void upload(File f,String title) throws OpenOfficeException, InternalException, ConnectionException{
        
        final OpenOfficeWorkbook owbk=OpenOfficeAdapter.getCurrentWorkbook();
        if (f==null){
            f=OpenOfficeAdapter.saveDocumentInTempFile(owbk,ExportType.XLS);
        }
        final File tmpFile=f;
        if (title==null || "".equals(title)){
            title=owbk.getTitle();
        }
        final String documentTitle=title;
        //BUG: DOCUMENT MUST BE SAVED
        
       /* File tmm=OpenOfficeAdapter.getCurrentWorkbookFile();
        if (tmm!=null){
            tmm=OpenOfficeAdapter.saveSheetInTempFile(owbk,ExportType.XLS_EXPORT);
        }
        final File tmpFile=tmm;
        */
        ExceptionalRunner excRun=new ExceptionalRunner(){
            public Object runInternal() throws OpenOfficeException, InternalException, ConnectionException {
                GoogleAdapter.getAdapter().uploadFile(StateManager.getGoogle(),tmpFile,documentTitle);
                return null;
            }
            
        };
        try{
            executeExceptionalRunner(excRun);
        } catch(Exception ex){
            Throwable t=ex.getCause();
            if (t instanceof OpenOfficeException){
                throw (OpenOfficeException)t;
            }
            if (t instanceof InternalException){
                throw (InternalException)t;
            }
            if (t instanceof ConnectionException){
                throw (ConnectionException)t;
            }
            DirtyLogHelper.append(ex);
            DirtyLogHelper.append(t);
            throw new InternalException(t);
        }
        tmpFile.delete();
    }
    
    public static Object executeExceptionalRunner(ExceptionalRunner excRun) throws Exception{
        Thread thread = new Thread(excRun);
        thread.setContextClassLoader(StateManager.getHost().getClass().getClassLoader());
        thread.start();
        while (thread.isAlive()){
            try{
                thread.join();
            } catch(InterruptedException ex){
            }
        }
        if (excRun.getTopThrowable()!=null){
            DirtyLogHelper.append(excRun.getTopThrowable());
            throw new Exception(excRun.getTopThrowable());
        }
        return excRun.getReturnValue();
    }
    
    public Map<String,Object> getMapping(List<Document> googleDoc){
        Map<String,String> typeMapper=new HashMap<String,String>();
        typeMapper.put(Document.Type.PRESENTATION.toString(),"Presentations");
        typeMapper.put(Document.Type.SPREADSHEET.toString(),"Spreadsheets");
        typeMapper.put(Document.Type.TEXT.toString(),"Text documents");
        typeMapper.put(Document.Type.UNKNOWN.toString(),"Unsupported");
        Map<String,List<Document>> folders=new HashMap<String,List<Document>>();
        Map<String,List<Document>> docTypes=new HashMap<String,List<Document>>();
        for(Document doc:googleDoc){
            if (doc instanceof GoogleDocument){
                GoogleDocument gdoc=(GoogleDocument)doc;
                String type=typeMapper.get(gdoc.getType().toString());
                putMap(docTypes,type,gdoc);
                Set<String> flds=gdoc.getFolders();
                for(String fldr:flds){
                    putMap(folders,fldr,gdoc);
                }
            }
        }
        Map<String,Object> retMap=new HashMap<String,Object>();
        retMap.put("Document types",docTypes);
        retMap.put("Folders",folders);
        return retMap;
    }
    
    protected static void putMap(Map<String,List<Document>> map, String key, Document doc){
        List<Document> dList=map.get(key);
        if (dList==null){
            dList=new ArrayList<Document>();
            map.put(key,dList);
        }
        dList.add(doc);
    }
    
    public static void downloadDocAndOpen(GoogleDocument doc) throws InternalException{
        URL url=GoogleAdapter.getAdapter().downloadFile(StateManager.getGoogle(),doc);
        StateManager.storeCurrentDocument(OpenOfficeAdapter.showDocument(url),doc);
    }
}
